package my.org.swing.animate;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.util.Arrays;
import javax.swing.border.AbstractBorder;

public class LineBorder extends AbstractBorder {

    private static final long serialVersionUID = -3833112187516505456L;

    public static final int ALL = 15;
    public static final int TOP = 1;
    public static final int LEFT = 1 << 1;
    public static final int BOTTOM = 1 << 2;
    public static final int RIGHT = 1 << 3;

    private int edges = ALL;

    private Paint paint;

    private double lineWidth = 1;

    private int arc = 0;

    private int[] paddings = new int[4];
    private int[] margins = new int[4];

    public LineBorder() {
        this(new Color(224, 224, 230));
    }

    public LineBorder(Paint paint) {
        this(ALL, paint);
    }

    public LineBorder(int edges, Paint paint) {
        this.paint = paint;
        this.edges = edges;
    }

    public LineBorder(Paint paint, double lineWidth) {
        this.paint = paint;
        this.lineWidth = lineWidth;
    }


    protected Paint getPaint() {
        return paint;
    }

    public LineBorder setPadding(int... p) {
        if (p == null || p.length == 0) {
            return this;
        }

        if (p.length == 1) {
            Arrays.fill(paddings, p[0]);
        } else if (p.length == 2) {
            paddings[0] = paddings[2] = p[0];
            paddings[1] = paddings[3] = p[1];
        } else if (p.length == 3) {
            paddings[0] = p[0];
            paddings[1] = p[1];
            paddings[2] = p[2];
            paddings[3] = p[1];
        } else if (p.length > 3) {
            paddings[0] = p[0];
            paddings[1] = p[1];
            paddings[2] = p[2];
            paddings[3] = p[3];
        }

        return this;
    }

    public LineBorder setMargin(int... m) {
        if (m == null || m.length == 0) {
            return this;
        }

        if (m.length == 1) {
            Arrays.fill(margins, m[0]);
        } else if (m.length == 2) {
            margins[0] = margins[2] = m[0];
            margins[1] = margins[3] = m[1];
        } else if (m.length == 3) {
            margins[0] = m[0];
            margins[1] = m[1];
            margins[2] = m[2];
            margins[3] = m[1];
        } else if (m.length > 3) {
            margins[0] = m[0];
            margins[1] = m[1];
            margins[2] = m[2];
            margins[3] = m[3];
        }

        return this;
    }

    public LineBorder setLineWidth(int lineWidth) {
        if (lineWidth > 0 && lineWidth < 50) {
            this.lineWidth = lineWidth;
        }

        return this;
    }

    public LineBorder setEdges(int edges) {
        if (edges >= 0 && edges < 16) {
            this.edges = edges;
        }

        return this;
    }

    public LineBorder setArc(int arc) {
        arc = arc < 0 ? 0 : arc;
        this.arc = arc;

        return this;
    }

    @Override
    public Insets getBorderInsets(Component c) {
        return getBorderInsets(c, new Insets(0, 0, 0, 0));
    }

    @Override
    public Insets getBorderInsets(Component c, Insets insets) {
        insets.top = (int) (paddings[0] + margins[0] + ((edges & TOP) > 0 ? lineWidth : 0));
        insets.left = (int) (paddings[1] + margins[1] + ((edges & LEFT) > 0 ? lineWidth : 0));
        insets.bottom = (int) (paddings[2] + margins[2] + ((edges & BOTTOM) > 0 ? lineWidth : 0));
        insets.right = (int) (paddings[3] + margins[3] + ((edges & RIGHT) > 0 ? lineWidth : 0));

        return insets;
    }


    @Override
    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setPaint(getPaint());
        g2d.setStroke(new BasicStroke((float) lineWidth));
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 错了一个单位
        width--;
        height--;

        int stroke = (int) (lineWidth / 2); // 笔画宽度考虑进去
        if (edges == 15 && arc > 0) {
            x = x + margins[1] + stroke;
            y = y + margins[0] + stroke;
            width = width - margins[3] - stroke;
            height = height - margins[2] - stroke;
            g2d.drawRoundRect(x, y, width, height, arc, arc);
            return;
        }

        int x1, x2, y1, y2;
        int left = 0, top = 0, bottom = 0;
        if ((edges & TOP) > 0) {
            x1 = x + margins[1] + stroke;
            y1 = y + margins[0] + stroke;
            x2 = x + width - margins[3] - stroke;
            y2 = y1;
            g2d.drawLine(x1, y1, x2, y2);

            top = stroke;
        }

        if ((edges & LEFT) > 0) {
            x1 = x + margins[1] + stroke;
            y1 = y + margins[0] + stroke + top;
            x2 = x1;
            y2 = y + height - margins[2] - stroke;
            g2d.drawLine(x1, y1, x2, y2);

            left = stroke;
        }

        if ((edges & BOTTOM) > 0) {
            x1 = x + margins[1] + stroke + left;
            y1 = y + height - margins[2] - stroke;
            x2 = x + width - margins[3] - stroke;
            y2 = y1;
            g2d.drawLine(x1, y1, x2, y2);

            bottom = stroke;
        }

        if ((edges & RIGHT) > 0) {
            x1 = x + width - margins[3] - stroke;
            y1 = y + margins[0] + stroke + top;
            x2 = x1;
            y2 = y + height - margins[2] - stroke - bottom;
            g2d.drawLine(x1, y1, x2, y2);
        }
    }
}